library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity coder is
    Port ( start, clk, rst : in std_logic;
           datain, key : in std_logic_vector (127 downto 0);
           dataout : out std_logic_vector (127 downto 0);
           finish : out std_logic;
			  
			  tst2, tst1, tst0: out std_logic_vector(255 downto 0));
end coder;

architecture Structural of coder is
	constant nr_of_rounds: integer := 10;
	-- opoznienie w taktach, ile czasu zajmuje przetworzenie jednego bloku
	constant block_delay: natural := 62;
	
	-- sygnal laczacy kolejne rundy
	type connect_round is array (nr_of_rounds - 1 downto 0) of std_logic_vector (127 downto 0);
	signal after_round : connect_round;

	-- klucze dla poszczegolnych rund
	type subkeys is array (nr_of_rounds downto 1) of std_logic_vector (127 downto 0);
	signal subkey : subkeys;
	
	-- sygnaly dla ostatniej rundy
	signal after_data_in_switch, before_out_data_switch, after_key_switch, after_subbytes, 
				after_shiftrows, result : std_logic_vector (127 downto 0);
	
	signal dataout_buf : std_logic_vector (127 downto 0);	-- TODO wywalic
begin

-- Sygnaly do ChipScope
--	tst0 <= after_round(9)(127 downto 96) & after_round(8)(127 downto 96) & after_round(7)(127 downto 96) & 
--				after_round(6)(127 downto 96) & after_round(5)(127 downto 96)	& after_round(4)(127 downto 96) & 
--				after_round(3)(127 downto 96) & after_round(2)(127 downto 96);
--	tst1(255 downto 128) <= after_round(1)(127 downto 96) & after_round(0)(127 downto 96) & 
--									after_subbytes(127 downto 96) & after_shiftrows(127 downto 96);
	tst0  <= datain & X"0000_0000_0000_0000_0000_0000_0000_0000";
	tst1  <= key & X"0000_0000_0000_0000_0000_0000_0000_0000";
	tst2  <= dataout_buf & X"0000_0000_0000_0000_0000_0000_0000_0000";

	-- Zmiana kolejnosci podawania danych (koder pracuje na danych podawanych wierszami,
	-- standard przewiduje podawanie danych kolumnami)
	KeySwitch: entity work.data_order(Behavioral)
		port map (datain => key,
					 dataout => after_key_switch);
	
	DataInSwitch: entity work.data_order(Behavioral)
		port map (datain => datain,
					 dataout => after_data_in_switch);

	-- Poczatkowe dodanie klucza
	AddKeyStart: entity work.addkey(Behavioral)
		port map (clk => clk,
					 datain => after_data_in_switch,
					 subkey => after_key_switch,
					 dataout => after_round(0));

	-- Rundy
	Gen_Rounds:
		for I in 1 to nr_of_rounds - 1 generate
			Round: entity work.round_code(Behavioral)
				port map (clk => clk,
							 rst => rst,
							 
							 datain => after_round(I - 1),
							 key => subkey(I),
							 dataout => after_round(I));
		end generate Gen_Rounds;
		
	-- Rozwijanie klucza
	Genkey1: entity work.Gen_key(Behavioral)
			port map (key_in => after_key_switch, 
						 subkey => subkey(1),
						 clk => clk, 
						 r => X"01");
		
	Gen_KeyExp:
		for I in 2 to nr_of_rounds generate
		Genkey: entity work.Gen_key(Behavioral)
				port map (key_in => subkey(I - 1),  
							 subkey => subkey(I),
							 clk => clk, 
							 r => std_logic_vector(to_unsigned(I, 8)));
	   end generate Gen_KeyExp;
		
	-- Ostatnia runda (bez mixcolumn)
	Gen_Sbox:
		for I in 0 to 15 generate
			SubBytes: entity work.sbox(Behavioral)
				port map (clk => clk, 
							 datain => after_round(nr_of_rounds - 1)(((I + 1)*8 - 1) downto I * 8),
							 dataout => after_subbytes(((I + 1)*8 - 1) downto I * 8));
		end generate Gen_Sbox;

	ShiftRows: entity work.shrows(Behavioral)
		port map (clk => clk,
					 datain => after_subbytes,
					 dataout => after_shiftrows);
	
	AddKeyFinal: entity work.addkey(Behavioral)
		port map (clk => clk,
					 datain => after_shiftrows,
					 subkey => subkey(nr_of_rounds),
					 dataout => before_out_data_switch);
					 
	-- Zmiana kolejnosci odbierania danych (koder pracuje na danych podawanych wierszami,
	-- standard przewiduje odbieranie danych kolumnami)
	DataOutSwitch: entity work.data_order(Behavioral)
		port map (datain => before_out_data_switch,
					 dataout => dataout_buf);

	-- Propaguje sygnal start, aby na koncu oznaczyc finish
	FinishSignal: entity work.start_to_finish(Behavioral)
		generic map ( delay => block_delay )
		port map (start => start,
					 clk => clk,
					 rst => rst,
					 finish => finish);

dataout <= dataout_buf; -- TODO wywalic
end Structural;
